package com.ayf.payment.game.api.httpclient;


import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.utils.AESCoder;
import com.ayf.payment.game.api.utils.CommonResult;
import com.ayf.payment.game.api.utils.EncryptedRandomKey;
import com.ayf.payment.game.api.utils.JsonUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * @Description: HttpClient封装类
 * @Author: zh-liang
 * @Date : 2019-12-12 18:47
 */
@Component
public class HttpClientUtils {

    private static StringRedisTemplate stringRedisTemplate;

    @Autowired
    public HttpClientUtils(StringRedisTemplate stringRedisTemplate){
        this.stringRedisTemplate = stringRedisTemplate;
    }

    private static final String retryReq = "retryReq";
    private static final long retryReqCount = 2;

    public static CommonResult<T> doPostGetWay(String url, Object t, String privateKeys, String traceId, int socketTimeoutSecond) throws Exception {
        LogPortal.info("{} 请求支付网关URL:{}", traceId, url);
        String params = JsonUtils.toJson(t);
        LogPortal.info("{} 请求支付网关参数:{}", traceId, params);

        if (socketTimeoutSecond==0){
            socketTimeoutSecond = 120;
        }

        RequestConfig requestConfig = RequestConfig.custom().
                setConnectTimeout(10 * 1000).
                setConnectionRequestTimeout(10 * 1000).
                setSocketTimeout(socketTimeoutSecond*1000). //超时最大等待时间 单位:秒
                build();
        CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
        if (url.startsWith("https")){
            client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
                    .setSSLSocketFactory(new SSLConnectionSocketFactory(getSslContext())).build();
        }
        HttpPost post = new HttpPost(url);
        // AES加密密码每次动态获取
        String aesPwd= EncryptedRandomKey.getEncryptedRandomKey();
        String header = RSA.encrypt(aesPwd, privateKeys);
        post.setHeader("EncryptedInformation", header);
        post.setHeader("EncryptedPlatformCode","pinganvyhks8dZsPZQHXLmKxbJBf0EMcOaAbDc");
        post.setConfig(MyRequestConfig.getRequestConfig());
        post.setHeader("Content-Type", "application/json;charset=UTF-8");
        post.setHeader("Connection","close");
        String encryptParams = AESCoder.aes128EncryptUtf8(params,aesPwd);
        LogPortal.debug("{} 加密密码原文:{}",traceId,aesPwd);
        LogPortal.debug("{} 密码RSA加密后:{}",traceId,header);
        LogPortal.debug("{} body加密后:{}",traceId,encryptParams);
        StringEntity stringEntity = new StringEntity(encryptParams, "UTF-8");
        stringEntity.setContentType("text/json");
        post.setEntity(stringEntity);

        CloseableHttpResponse response = null;
        long startTime = System.currentTimeMillis();
        try {
            response = client.execute(post);
            if (response != null) {
                int responseCode = response.getStatusLine().getStatusCode();
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    String str = EntityUtils.toString(response.getEntity(), "utf-8");
                    long endTime = System.currentTimeMillis();
                    LogPortal.error("{} 请求支付网关结束，耗时:{}ms，responseCode={} 返回报文:{}", traceId, (endTime - startTime),responseCode,str);
                    return JsonUtils.fromJson(str, CommonResult.class);
                }
            }
        } catch (ConnectTimeoutException e) {
            String key = retryReq.concat(traceId);
            Long increment = stringRedisTemplate.opsForValue().increment(key, 1);
            stringRedisTemplate.expire(key,5L, TimeUnit.MINUTES);
            if (increment<=retryReqCount){
                LogPortal.info("{} 重试请求次数 {}",key,increment);
                return doPostGetWay(url,t,privateKeys,traceId,socketTimeoutSecond);
            }
            stringRedisTemplate.delete(key);
            LogPortal.error("{} 请求支付网关发生ConnectTimeoutException异常，具体原因:{}",traceId, e.getMessage());
            JSONObject resJson = new JSONObject();
            resJson.put("code", "800");
            resJson.put("msg", "调用支付网关发生异常，errCode:" + traceId);
            return JsonUtils.fromJson(resJson.toJSONString(), CommonResult.class);
        }catch (SocketTimeoutException e) {
            LogPortal.error("{} 请求支付网关发生SocketTimeoutException异常，具体原因:{}",traceId, e.getMessage());
            JSONObject resJson = new JSONObject();
            resJson.put("code", "801");
            resJson.put("msg", "调用支付网关发生异常，errCode:" + traceId);
            return JsonUtils.fromJson(resJson.toJSONString(), CommonResult.class);
        }catch (Exception e) {
            LogPortal.error("{} 请求支付网关发生{}异常，具体原因:{}", e, traceId, e.getClass().getName(), e.getMessage());
            JSONObject resJson = new JSONObject();
            resJson.put("code", "802");
            resJson.put("msg", "调用支付网关发生异常，errCode:" + traceId);
            return JsonUtils.fromJson(resJson.toJSONString(), CommonResult.class);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                LogPortal.error("{} 关闭请求支付网关连接发生{}异常", e, traceId, e.getClass().getName());
            }
        }
        return null;
    }

    public static CommonResult<T> doPostGetWay(String url, Object t, String privateKeys, String traceId) throws Exception {
       return doPostGetWay(url,t,privateKeys,traceId,180);
    }

    private static SSLContext getSslContext() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }}, new SecureRandom());
        return sslContext;
    }
}
